/* 
 * Copyright (c)	Insighten Intelligent Equipment co.,LTD
 * 
 *  Use of this software is controlled by the terms and conditions found
 *  in the license agreement under which this software has been supplied.
 * 
 */
/** 
 * @file main.c
 * @brief server of wireles player project
 * @author taco [tacoee@gmail.com]
 * @version 0.1
 * @date 2010-09-08
 */

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/select.h>
#include <sys/types.h>
#include <sys/time.h>
#include <pthread.h>

#include "udp_thread.h"
#include "tcp_server.h"
#include "udp_lib.h"
#include "rwbuf.h"
#include "main.h"

static int quit = 0;

int set_quit()
{
	quit = 1;
}
int get_quit()
{
	return quit;
}

void helper(char *program)
{
	fprintf(stderr, "Usage: %s tcpport[1234] udpport[2345]\n", program);
}


Request *req_head= NULL;
fd_set rset;
fd_set wset;
int maxfd = -1;

Request *new_request_process(TcpServer *s, SocketAttr *attr)
{
	Request *newreq = NULL;
	
	newreq = tcp_server_request(s, attr);
	newreq->buf = buf_new(NULL, NULL);
	buf_init(newreq->buf, BUFSIZE);

	REQ_FD_SET(newreq->fd, &rset);
	request_enqueue(&req_head, newreq);

	return newreq;
}

Ret data_request_process(Request *req)
{
	return_val_if_fail(req != NULL, RET_FAIL);

	int retval;

	switch (req->status) {
		case READ_HEADER:
		case ONE_CR:
		case ONE_LF:
		case TWO_CR:
			retval = read_header(req);
			break;
		case BODY_READ:	
		case BODY_WRITE:
		case DONE:
			FD_CLR(req->fd, &rset);
			break;
		default:
			break;
	}

	switch(retval) {
		case -1:	/*error*/
			request_dequeue(&req_head, req);
			break;
		case 1:		/*more to do*/
			break;
		case 0:		/*compelet this request*/
			FD_CLR(req->fd, &wset);
			request_dequeue(&req_head, req);
			/*maybe need put to free request list*/
			break;
		default:
			break;
	}
	return RET_OK;
}

int main(int argc, char *argv[])
{
	TcpServer *tcp_svr;
	UdpSocket *udp_svr;
	SocketAttr attr = {0, 8092};
	UdpSvrEnv *udp_svr_env = NULL;
	RwBuf *buf;
	Request *req = NULL;
	Request *req_pos = NULL;
	int ret = -1;
	int i;
	int clifd = -1;
	int tcpport;
	int udpport;
	char *lckaddr = inet_ntoa(net_get_ip("eth0"));
	char *remaddr = NULL;
	pthread_t	udp_thread;

	if (argc < 3) {
		helper(argv[0]);
		exit(1);
	}

	tcpport = atol(argv[1]);
	udpport = atol(argv[2]);

	FD_ZERO(&rset);
	FD_ZERO(&wset);

	udp_svr_env = udp_svr_env_new();
	tcp_svr = tcp_server_new();
	udp_svr = udp_socket_new();

	udp_socket_init(udp_svr,lckaddr,NULL, udpport,&attr);
	tcp_server_init(tcp_svr, tcpport, 10, &attr);
	udp_svr_env_init(udp_svr_env, udp_svr);
	udp_svr_env_set_lckaddr(udp_svr_env, lckaddr);
#ifdef CONFIG_SCHED_PRIORITY
	pthread_attr_t	pattr;
	struct sched_param sparam;
	sparam.sched_priority = sched_get_priority_max(SCHED_FIFO);
	if (sparam.sched_priority == -1) {
		err_log("Get sched priority.");
		goto cleanup;
	}
	if (pthread_attr_setschedparam(&pattr, &sparam)) {
		err_log("Set sched priority");
		goto cleanup;
	}
	if (pthread_create(&udp_thread, &pattr, udp_svr_thread, (void*)udp_svr_env)) {
		err_log("Create thread error");
		goto cleanup;
	}
#else
	if (pthread_create(&udp_thread, NULL, udp_svr_thread, (void*)udp_svr_env)) {
		err_log("Create thread error");
		goto cleanup;
	}
#endif /*CONFIG_SCHED_PRIORITY*/
	tcp_server_create(tcp_svr);

	REQ_FD_SET(tcp_svr->fd, &rset);

	while(!get_quit()) {
		maxfd = -1;
		REQ_FD_SET(tcp_svr->fd, &rset);
		ret = select(maxfd+1, &rset, &wset, NULL, NULL);
		if (FD_ISSET(tcp_svr->fd, &rset)) {
			req = new_request_process(tcp_svr, &attr);			
			dbg_log("New request coming");
		}
		for(req_pos=req_head; req_pos != NULL; req_pos=req_pos->next) {
			data_request_process(req_pos);
		} /*for*/
	} /*while*/

cleanup:

	tcp_server_destroy(tcp_svr);
	udp_svr_env_destroy(udp_svr_env);
	udp_socket_destroy(udp_svr);

	return 0;
}

